package com.zlj.jdbc.utils.transaction;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/*
 * 添加事务之后的JdbcUtils
 */
public class JdbcUtils04 {
	private static Properties properties = null;
	private static Connection conn = null;
	private static PreparedStatement pstm = null;
	private static ResultSet resultSet = null;
	
	//事务的专用连接
    //ThreadLocal保证每个线程都有一个单独的连接
	private static ThreadLocal<Connection> t1 = new ThreadLocal<Connection>();
	
	private JdbcUtils04() {
		init();
	}

	private void init() {
		try {
			InputStream in = JdbcUtils04.class.getClassLoader().getResourceAsStream("db.properties");
			properties = new Properties();
			properties.load(in);
			Class.forName(properties.getProperty("dirverClassName"));
		} catch (ClassNotFoundException | IOException e) {
			e.printStackTrace();
		}
	}

	private static class LazyLoader {
		private static JdbcUtils04 INSTANCE = new JdbcUtils04();
	}

	public static JdbcUtils04 getInstance() {
		return LazyLoader.INSTANCE;
	}

	/*
	 * 获取数据库连接
	 */
	public Connection getConnection() throws SQLException {
		Connection conn = t1.get();   //获取当前线程的专用连接
    	//若conn不为null，说明已经调用了beginTransaction()方法，表示已经开启了事务
    	if(conn != null) {
    		return conn;
    	} else {
    		conn = DriverManager.getConnection(properties.getProperty("jdbcUrl"), properties.getProperty("username"), properties.getProperty("password"));
    		return conn;
    	}
	}
	
	 /*
     * 开启事务：
     * 1、获取一个Connection,设置它的setAutoCommit(false);
     * 2、保证dao中使用的连接是上面创建的那个
     * 
     * ----------------------
     * 创建一个Connection，设置为手动提交
     * 把这个Connection给dao用
     * 并且commitTransaction 和  rollbackTransaction都可以获取的到
     */
    public void beginTransaction() throws SQLException {
    	Connection conn = t1.get();
    	if(conn != null) {
    		throw new SQLException("已经开启了事务，就不要重复开启了！");
    	}
    	/*
    	 * 1、给conn赋值；
    	 * 2、给conn设置为手动提交；
    	 */
    	conn = getConnection();  //给conn赋值，表示事务已经开启
    	conn.setAutoCommit(false);
    	t1.set(conn);  //把当前线程的连接保存起来
    }
    
    /**
     * 提交事务
     * 1、获取beginTransaction中获取的Connection，然后调用commit方法
     * @throws SQLException 
     */
    public void commitTransaction() throws SQLException {
    	Connection conn = t1.get();
    	if(conn == null) {
    		throw new SQLException("还没有开启事务，不能提交！");
    	}
    	conn.commit();
    	conn.close();
    	t1.remove();
    }
    
    /**
     * 回滚事务
     * 1、获取beginTransaction中获取的Connection，然后调用rollback方法
     * @throws SQLException 
     */
    public void rollbackTransaction() throws SQLException {
    	Connection conn = t1.get();
    	if(conn == null) {
    		throw new SQLException("还没有开启事务，不能回滚！");
    	}
    	conn.rollback();
    	conn.close();
    	t1.remove();
    }
    
    /**
     * 释放事务
     */
    public void releaseTransaction(Connection connection) {
    	Connection conn = t1.get();
    	if(conn == null) {
    		try {
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
    	}
    	
    	if(conn != connection) {
    		try {
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
    	}
    }
	
	/*
	 * 释放数据库连接
	 */
	public void releaseConnection() {
		try {
			if (resultSet != null) {
				resultSet.close();
			}

			if (pstm != null) {
				pstm.close();
			}

			if (conn != null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
